(ns clj-gallery.routes.upload
  (:require [compojure.core :refer [defroutes GET POST DELETE]]
            [ring.util.response :refer [file-response]]
            [hiccup.form :refer :all]
            [hiccup.element :refer [image]]
            [hiccup.util :refer [url-encode]]
            [noir.io :refer [upload-file resource-path]]
            [noir.response :as resp]
            [noir.util.route :refer [restricted]]
            [taoensso.timbre :refer [trace debug info warn error fatal]]
            [clojure.java.io :as io]
            [clojure.pprint :refer :all]

            [clj-gallery.views.layout :as layout]
            [clj-gallery.models.db :as db]
            [clj-gallery.util :refer [login-user-id galleries gallery-path thumb-prefix thumb-uri]])
  (:import (java.io File)
           (java.net URLDecoder)
           (java.awt.geom AffineTransform)
           (java.awt.image AffineTransformOp BufferedImage)
           (javax.imageio ImageIO)))

(println "loading upload")

(def thumb-size 200)

(defn delete-image [userid name]
  (try
    (db/delete-image userid name)
    (io/delete-file (str (gallery-path) File/separator name))
    (io/delete-file (str (gallery-path) File/separator thumb-prefix name))
    "ok"
    (catch Exception ex
      (error ex "an error has occured while deleteing" name)
      (.getMessage ex))))

(defn delete-images [names]
  (let [userid (login-user-id)]
    (resp/json
      (for [name names]
        {:name name :status (delete-image userid name)}))))

(defn scale [img-src ratio width height]
  (let [scale (AffineTransform/getScaleInstance (double ratio) (double ratio))
        transform-op (AffineTransformOp. scale AffineTransformOp/TYPE_NEAREST_NEIGHBOR)]
    (.filter transform-op img-src (BufferedImage. width height (.getType img-src)))))

(defn scale-image [file]
  (let [img (ImageIO/read file)
        img-width (.getWidth img)
        img-height (.getHeight img)
        ratio (/ thumb-size img-height)
        cpt-width (int (* img-width ratio))
        cpt-height thumb-size]
    (scale img ratio cpt-width cpt-height)))

(defn save-thumbnail [{:keys [filename]}]
  (let [path (str (gallery-path) File/separator)]
    (ImageIO/write
      (scale-image (io/input-stream (str path filename)))
      "jpeg"
      (File. (str path thumb-prefix filename)))))

#_(defn upload-page [info]
    (layout/common
      [:h2 "Upload an image"]
      [:p info]
      (form-to {:enctype "multipart/form-data"}
               [:post "/upload"]
               (file-upload :file)
               (submit-button "upload"))))

(defn upload-page [params]
  (layout/render "upload.html" params))

#_(defn handle-upload [{:keys [filename] :as file}]
    (upload-page
      (if (empty? filename)
        "please select a file to upload"

        (try
          (upload-file (gallery-path) file :create-path? true)
          (save-thumbnail file)
          (db/add-image (login-user-id) filename)
          (image {:height "150px"}
                 (thumb-uri (login-user-id) filename))
          (catch Exception ex
            (str "error uploading file " (.getMessage ex)))))))

(defn handle-upload [{:keys [filename] :as file}]
  (upload-page
    (if (empty? filename)
      {:error "please select a file to upload"}
      (try
        (upload-file (gallery-path) file)
        (save-thumbnail file)
        (db/add-image (login-user-id) filename)
        {:image (thumb-uri (login-user-id) filename)}
        (catch Exception ex
          (error ex "an error has occured while uploading" name)
          {:error (str "error uploading file " (.getMessage ex))})))))

(defn serve-file [user-id file-name]
  (let [filename (URLDecoder/decode file-name)]
    (file-response (str galleries File/separator user-id File/separator filename))))

(defroutes upload-routes
  (GET "/img/:user-id/:file-name" [user-id file-name] (serve-file user-id file-name))
  (GET "/upload" [info] (restricted (upload-page {:info info})))
  (POST "/upload" [file] (restricted (handle-upload file)))
  (POST "/delete" [names] (restricted (delete-images names))))